package ruledao

import (
	"vpn-management-server/logger"
	"vpn-management-server/src/dao"
	"vpn-management-server/src/model/rulemodel"
)

func AddRule(rule *rulemodel.Rule) error {
	sqlStr := "INSERT INTO rule(name,ip,mask,start_port,end_port,url_suffix,is_min,is_inner,signer,description) value(?,?,?,?,?,?,?,?,?,?)"
	if _, err := dao.GMysqlDB.Conn.Exec(sqlStr, rule.Name, rule.IP, rule.Mask, rule.StartPort, rule.EndPort, rule.UrlSuffix, rule.IsMIN, rule.IsInner, rule.Signer, rule.Description); err != nil {
		logger.Logger.Error(err)
		return err
	}
	return nil
}

func HasRule(name string) bool {
	var rule rulemodel.Rule
	sqlStr := "SELECT * FROM rule where name = ?"
	err := dao.GMysqlDB.Conn.Get(&rule, sqlStr, name)
	if err == nil {
		return true
	}
	return false
}

func GetRulesByPage(pageSize int, pageNo int) []*rulemodel.Rule {
	start := pageSize * (pageNo - 1)
	var rules []*rulemodel.Rule
	sqlStr := "SELECT * from rule LIMIT ?,?"
	if err := dao.GMysqlDB.Conn.Select(&rules, sqlStr, start, pageSize); err != nil {
		logger.Logger.Error(err)
		return nil
	}
	return rules
}

func GetUserRulesByPage(pageSize int, pageNo int, uid int) []*rulemodel.Rule {
	start := pageSize * (pageNo - 1)
	var rulesIDs []int
	sqlStr := "SELECT r_id from user_rules WHERE u_id = ? LIMIT ?,?"
	if err := dao.GMysqlDB.Conn.Select(&rulesIDs, sqlStr, uid, start, pageSize); err != nil {
		logger.Logger.Error(err)
		return nil
	}
	var rules []*rulemodel.Rule
	for _, id := range rulesIDs {
		if rule := GetRuleByID(id); rule != nil {
			rules = append(rules, rule)
		}
	}
	return rules
}

func GetUserRules(uid int) []*rulemodel.Rule {
	var rulesIDs []int
	sqlStr := "SELECT r_id from user_rules WHERE u_id = ? "
	if err := dao.GMysqlDB.Conn.Select(&rulesIDs, sqlStr, uid); err != nil {
		logger.Logger.Error(err)
		return nil
	}
	var rules []*rulemodel.Rule
	for _, id := range rulesIDs {
		if rule := GetRuleByID(id); rule != nil {
			rules = append(rules, rule)
		}
	}
	return rules
}

func GetRuleByID(id int) *rulemodel.Rule {
	var rule rulemodel.Rule
	sqlStr := "SELECT * from rule where id = ?"
	if err := dao.GMysqlDB.Conn.Get(&rule, sqlStr, id); err != nil {
		logger.Logger.Error(err)
		return nil
	}
	return &rule
}

func GetRuleInfoByID(id int) *rulemodel.RuleInfo {
	var RuleInfo rulemodel.RuleInfo
	sqlStr := "SELECT id,name from rule where id = ?"
	if err := dao.GMysqlDB.Conn.Get(&RuleInfo, sqlStr, id); err != nil {
		logger.Logger.Error(err)
		return nil
	}
	return &RuleInfo
}

func GetAllRuleInfos() []*rulemodel.RuleInfo {
	var RuleInfos []*rulemodel.RuleInfo
	sqlStr := "SELECT id,name from rule"
	if err := dao.GMysqlDB.Conn.Select(&RuleInfos, sqlStr); err != nil {
		logger.Logger.Error(err)
		return nil
	}
	return RuleInfos
}

func GetUGroupRulesByPage(pageSize int, pageNo int, ugid int) ([]*rulemodel.Rule, []int) {
	start := pageSize * (pageNo - 1)
	var RevokedRules []*rulemodel.RevokedRule
	sqlStr := "SELECT r_id,isdeleted from ugroup_rules where ug_id = ?  LIMIT ?,? "
	if err := dao.GMysqlDB.Conn.Select(&RevokedRules, sqlStr, ugid, start, pageSize); err != nil {
		logger.Logger.Error(err)
		return nil, nil
	}
	var rules []*rulemodel.Rule
	var IsDeletedArray []int
	for _, RevokedRule := range RevokedRules {
		if rule := GetRuleByID(RevokedRule.RuleID); rule != nil {
			rules = append(rules, rule)
			IsDeletedArray = append(IsDeletedArray, RevokedRule.IsDeleted)
		}
	}
	return rules, IsDeletedArray
}

func UGroupGetRulesByPage(pageSize int, pageNo int, ugid int) []*rulemodel.Rule {
	start := pageSize * (pageNo - 1)
	var rulesIDs []int
	sqlStr := "SELECT r_id from ugroup_rules where ug_id = ? and isdeleted = ? LIMIT ?,? "
	if err := dao.GMysqlDB.Conn.Select(&rulesIDs, sqlStr, ugid, 0, start, pageSize); err != nil {
		logger.Logger.Error(err)
		return nil
	}
	var rules []*rulemodel.Rule
	for _, id := range rulesIDs {
		if rule := GetRuleByID(id); rule != nil {
			rules = append(rules, rule)
		}
	}
	return rules
}

func GetUGroupRuleInfos(ugid int) []*rulemodel.RuleInfo {
	var rulesIDs []int
	sqlStr := "SELECT r_id from ugroup_rules where ug_id = ? and isdeleted = ? "
	if err := dao.GMysqlDB.Conn.Select(&rulesIDs, sqlStr, ugid, 0); err != nil {
		logger.Logger.Error(err)
		return nil
	}
	var ruleInfos []*rulemodel.RuleInfo
	for _, id := range rulesIDs {
		if ruleInfo := GetRuleInfoByID(id); ruleInfo != nil {
			ruleInfos = append(ruleInfos, ruleInfo)
		}
	}
	return ruleInfos
}

func GetUGroupRules(ugid int) []*rulemodel.Rule {
	var rulesIDs []int
	sqlStr := "SELECT r_id from ugroup_rules where ug_id = ? "
	if err := dao.GMysqlDB.Conn.Select(&rulesIDs, sqlStr, ugid); err != nil {
		logger.Logger.Error(err)
		return nil
	}
	var rules []*rulemodel.Rule
	for _, id := range rulesIDs {
		if rule := GetRuleByID(id); rule != nil {
			rules = append(rules, rule)
		}
	}
	return rules
}

func GetRulesByRGroupID(rgid int) []*rulemodel.Rule {
	var IDs []int
	sqlStr := "SELECT r_id from rgroup_rules where rg_id = ?"
	if err := dao.GMysqlDB.Conn.Select(&IDs, sqlStr, rgid); err != nil {
		logger.Logger.Error(err)
		return nil
	}
	var rules []*rulemodel.Rule
	for _, id := range IDs {
		if rule := GetRuleByID(id); rule != nil {
			rules = append(rules, rule)
		}
	}
	return rules
}

func GetRuleIDsByRGroupID(rgid int) []int {
	var IDs []int
	sqlStr := "SELECT r_id from rgroup_rules where rg_id = ?"
	if err := dao.GMysqlDB.Conn.Select(&IDs, sqlStr, rgid); err != nil {
		logger.Logger.Error(err)
		return nil
	}
	return IDs
}

func GetRulesCount() int {
	var count int
	sqlStr := "SELECT COUNT(*) FROM rule"
	err := dao.GMysqlDB.Conn.Get(&count, sqlStr)
	if err != nil {
		logger.Logger.Error(err)
		return -1
	}
	return count
}

func GetUserRulesCount(uid int) int {
	var count int
	sqlStr := "SELECT COUNT(*) FROM user_rules where u_id = ?"
	err := dao.GMysqlDB.Conn.Get(&count, sqlStr, uid)
	if err != nil {
		logger.Logger.Error(err)
		return -1
	}
	return count
}

func GetUGroupRulesCount(ugid int) int {
	var count int
	sqlStr := "SELECT COUNT(*) FROM ugroup_rules where ug_id = ? "
	err := dao.GMysqlDB.Conn.Get(&count, sqlStr, ugid)
	if err != nil {
		logger.Logger.Error(err)
		return -1
	}
	return count
}

func UGroupGetRulesCount(ugid int) int {
	var count int
	sqlStr := "SELECT COUNT(*) FROM ugroup_rules where ug_id = ? and isdeleted =?"
	err := dao.GMysqlDB.Conn.Get(&count, sqlStr, ugid, 0)
	if err != nil {
		logger.Logger.Error(err)
		return -1
	}
	return count
}

func DeleteRules(IDs []int) error {
	tx, _ := dao.GMysqlDB.Conn.Begin()
	for _, id := range IDs {
		sqlStr := "DELETE FROM rule where id = ?"
		_, err := tx.Exec(sqlStr, id)
		if err != nil {
			logger.Logger.Error(err)
			tx.Rollback()
			return err
		}
	}
	return tx.Commit()
}

func DeleteRulesFromUGroup(IDs []int, ugid int) error {
	tx, _ := dao.GMysqlDB.Conn.Begin()
	for _, id := range IDs {
		sqlStr := "DELETE FROM ugroup_rules where r_id = ? and ug_id = ?"
		_, err := tx.Exec(sqlStr, id, ugid)
		if err != nil {
			logger.Logger.Error(err)
			tx.Rollback()
			return err
		}
	}
	return tx.Commit()
}

func RevokeRulesFromUGroup(IDs []int, ugid int) error {
	tx, _ := dao.GMysqlDB.Conn.Begin()
	for _, id := range IDs {
		sqlStr := "UPDATE  ugroup_rules SET isdeleted = ? WHERE r_id = ? and ug_id = ?"
		_, err := tx.Exec(sqlStr, 1, id, ugid)
		if err != nil {
			logger.Logger.Error(err)
			tx.Rollback()
			return err
		}
	}
	return tx.Commit()
}

func RecoverRulesFromUGroup(IDs []int, ugid int) error {
	tx, _ := dao.GMysqlDB.Conn.Begin()
	for _, id := range IDs {
		sqlStr := "UPDATE  ugroup_rules SET isdeleted = ? WHERE r_id = ? and ug_id = ?"
		_, err := tx.Exec(sqlStr, 0, id, ugid)
		if err != nil {
			logger.Logger.Error(err)
			tx.Rollback()
			return err
		}
	}
	return tx.Commit()
}

func DeleteRulesFromUGroupUser(IDs []int, UIDs []int) error {
	tx, _ := dao.GMysqlDB.Conn.Begin()
	for _, id := range IDs {
		for _, uid := range UIDs {
			sqlStr := "DELETE FROM user_rules where r_id = ? and u_id = ?"
			_, err := tx.Exec(sqlStr, id, uid)
			if err != nil {
				logger.Logger.Error(err)
				tx.Rollback()
				return err
			}
		}
	}
	return tx.Commit()
}

func DeleteRulesFromRGroup(IDs []int, rgid int) error {
	tx, _ := dao.GMysqlDB.Conn.Begin()
	for _, id := range IDs {
		sqlStr := "DELETE FROM rgroup_rules where r_id = ? and rg_id = ?"
		_, err := tx.Exec(sqlStr, id, rgid)
		if err != nil {
			logger.Logger.Error(err)
			tx.Rollback()
			return err
		}
	}
	return tx.Commit()
}

func DeleteRulesFromAllRGroup(IDs []int) error {
	tx, _ := dao.GMysqlDB.Conn.Begin()
	for _, id := range IDs {
		sqlStr := "DELETE FROM rgroup_rules where r_id = ?"
		_, err := tx.Exec(sqlStr, id)
		if err != nil {
			logger.Logger.Error(err)
			tx.Rollback()
			return err
		}
	}
	return tx.Commit()
}

func DeleteRulesFromAllUser(IDs []int) error {
	tx, _ := dao.GMysqlDB.Conn.Begin()
	for _, id := range IDs {
		sqlStr := "DELETE FROM user_rules where r_id = ? "
		_, err := tx.Exec(sqlStr, id)
		if err != nil {
			logger.Logger.Error(err)
			tx.Rollback()
			return err
		}
	}
	return tx.Commit()
}

func DeleteRulesFromAllUGroup(IDs []int) error {
	tx, _ := dao.GMysqlDB.Conn.Begin()
	for _, id := range IDs {
		sqlStr := "DELETE FROM ugroup_rules where r_id = ? "
		_, err := tx.Exec(sqlStr, id)
		if err != nil {
			logger.Logger.Error(err)
			tx.Rollback()
			return err
		}
	}
	return tx.Commit()
}

func GrantRuleToUGroup(IDs []int, ugid int, singer string) error {
	tx, _ := dao.GMysqlDB.Conn.Begin()
	for _, id := range IDs {
		sqlStr := "INSERT INTO ugroup_rules(ug_id,r_id,signer,isdeleted) value(?,?,?,?)"
		_, err := tx.Exec(sqlStr, ugid, id, singer, 0)
		if err != nil {
			logger.Logger.Error(err)
			tx.Rollback()
			return err
		}
	}
	return tx.Commit()
}

func HasRuleInUGroup(rid int, ugid int) bool {
	var rule rulemodel.Rule
	sqlStr := "SELECT * FROM ugroup_rules where ug_id = ? and r_id = ?"
	err := dao.GMysqlDB.Conn.Get(&rule, sqlStr, ugid, rid)
	if err == nil {
		return true
	}
	return false
}

func GrantRuleToUser(IDs []int, uid int, singer string) error {
	tx, _ := dao.GMysqlDB.Conn.Begin()
	for _, id := range IDs {
		sqlStr := "INSERT INTO user_rules(u_id,r_id,signer) value(?,?,?)"
		_, err := tx.Exec(sqlStr, uid, id, singer)
		if err != nil {
			logger.Logger.Error(err)
			tx.Rollback()
			return err
		}
	}
	return tx.Commit()
}

func HasRuleInUser(rid, uid int) bool {
	var rule rulemodel.Rule
	sqlStr := "SELECT * FROM user_rules where u_id = ? and r_id = ?"
	err := dao.GMysqlDB.Conn.Get(&rule, sqlStr, uid, rid)
	if err == nil {
		return true
	}
	return false
}

func DepriveRuleFromUser(IDs []int, uid int) error {
	tx, _ := dao.GMysqlDB.Conn.Begin()
	for _, id := range IDs {
		sqlStr := "DELETE FROM user_rules WHERE u_id = ? and r_id = ?"
		_, err := tx.Exec(sqlStr, uid, id)
		if err != nil {
			logger.Logger.Error(err)
			_ = tx.Rollback()
			return err
		}
	}
	return tx.Commit()
}

func DepriveAllRuleFromUser(uid int) error {
	sqlStr := "DELETE FROM user_rules WHERE u_id = ?"
	_, err := dao.GMysqlDB.Conn.Exec(sqlStr, uid)
	if err != nil {
		logger.Logger.Error(err)
		return err
	}
	return nil
}

func DepriveAllRuleFromUGroup(ugid int) error {
	sqlStr := "DELETE FROM ugroup_rules WHERE ug_id = ?"
	_, err := dao.GMysqlDB.Conn.Exec(sqlStr, ugid)
	if err != nil {
		logger.Logger.Error(err)
		return err
	}
	return nil
}

func GetRGroupRuleByPage(pageSize int, pageNo int, rgid int) []*rulemodel.Rule {
	var IDs []int
	start := (pageNo - 1) * pageSize
	sqlStr := "SELECT r_id from rgroup_rules where rg_id = ? LIMIT ?,?"
	if err := dao.GMysqlDB.Conn.Select(&IDs, sqlStr, rgid, start, pageSize); err != nil {
		logger.Logger.Error(err)
		return nil
	}
	var rules []*rulemodel.Rule
	for _, id := range IDs {
		if rule := GetRuleByID(id); rule != nil {
			rules = append(rules, rule)
		}
	}
	return rules
}

func GetRGroupRuleCount(rgid int) int {
	var count int
	sqlStr := "SELECT COUNT(*) FROM rgroup_rules where rg_id = ?"
	err := dao.GMysqlDB.Conn.Get(&count, sqlStr, rgid)
	if err != nil {
		logger.Logger.Error(err)
		return -1
	}
	return count
}

func DeleteRulesFromUGroupRGroup(rids, ugids []int) error {
	tx, _ := dao.GMysqlDB.Conn.Begin()
	sqlStr := "DELETE FROM user_rules WHERE u_id = ? and r_id = ?"
	for _, uid := range ugids {
		for _, rid := range rids {
			_, err := tx.Exec(sqlStr, uid, rid)
			if err != nil {
				logger.Logger.Error(err)
				tx.Rollback()
				return err
			}
		}
	}
	return tx.Commit()
}
